home *** CD-ROM | disk | FTP | other *** search
/ Directorty Opus 5 - Magellan 2 / Opus 5 - Magellan 2.iso / Extras / hotlist_source / source / ResourceNodes.c < prev    next >
C/C++ Source or Header  |  1996-10-02  |  15KB  |  383 lines

  1. /*######################################################################################
  2. ## ResourceNode Functions & Structures, by Leo Davidson                                  ##
  3. ## Functions for easy allocation, openning, closing, freeing, etc.                      ##
  4. ##                                                                                      ##
  5. ## This version uses the memory pool routines in dopus5.library, not the exec ones.      ##
  6. ##                                                                                      ##
  7. ## Tabsize: 4 -- Amiga-specific -- Compile with SAS/C.                                  ##
  8. ########################################################################################
  9. $VER: ResourceNodes.c 1.2 (2.10.96)
  10.  
  11.    All routines take a pointer to a ResNode_Data structure. Initially, this
  12.    should be all NULLs except for poolhead which must be set up as the Header
  13.    for a memory pool. MEMF_CLEAR *must* be turned on for this pool.
  14.    It is up to you to free the pool once you're finished using ResNodes.
  15.    Other routines are free to use the pool, but if you have more than one pointer
  16.    to it, make sure they all get NULLed when the pool is freed.
  17.  
  18.    All close/free/etc. routines should be safe to call when nothing needs to be
  19.    closed/freed/etc.
  20.  
  21. ****************************************************************************************
  22.  
  23. Although these routines and related structures are more-or-less stand alone, the
  24. intention is that a customised version of them will be used for each project. This
  25. means that one isn't tied down by forced compatibility with other situations and
  26. environments.
  27.  
  28. ***************************************************************************************/
  29.  
  30. #include "hotlist.module.h"
  31.  
  32. /*====================================================================================-.
  33. || Optional Functions                                                                  ||
  34. `-====================================================================================*/
  35. #define ResNodes_Allocate
  36. #define ResNodes_Lock
  37. #define ResNodes_Examine
  38. //#define ResNodes_Open
  39. //#define ResNodes_DeleteFile
  40.  
  41. /**************************************************************************************/
  42.  
  43. /*= CreateResNode() ==================================================================-.
  44. || Attempts to allocate a new ResNode structure. Returns pointer to new, cleared      ||
  45. || ResNode, or NULL on failure. Updates the linked list of ResNodes.                  ||
  46. `-====================================================================================*/
  47. ResNode *createResNode(ResNode_Data *rnd)
  48. {
  49.     ResNode *newResNode;
  50.  
  51.     if ( newResNode = AllocMemH(rnd->poolhead,sizeof(ResNode)) )
  52.     {
  53.         newResNode->rn_Next = rnd->resnode_base;        // Update list pointers
  54.         if (rnd->resnode_base)
  55.             rnd->resnode_base->rn_Prev = newResNode;
  56.         rnd->resnode_base = newResNode;
  57.     }
  58.     return newResNode;
  59. }
  60.  
  61. /*= DeleteResNode() ==================================================================-.
  62. || Delete a ResNode and all free all things connected with it.                          ||
  63. || You should not use the ResNode pointer's value again after calling this routine.      ||
  64. ||                                                                                      ||
  65. || Note: Failure to close/deallocate/whatever anything may result in a requester to      ||
  66. ||       the user but will not cause a different return value.                          ||
  67. `-====================================================================================*/
  68. void deleteResNode(ResNode_Data *rnd, ResNode *doomedResNode)
  69. {
  70.     if (doomedResNode)
  71.     {
  72. /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -*/
  73. /* Insert calls to new close/deallocate/whatever functions here.                      */
  74. /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -*/
  75. #ifdef ResNodes_Lock
  76.     unlockFileResNode(rnd,doomedResNode);
  77. #endif
  78. #ifdef ResNodes_Examine
  79.     freeFIBResNode(rnd,doomedResNode);
  80. #endif
  81. #ifdef ResNodes_Open
  82.     closeFileResNode(rnd,doomedResNode);
  83. #endif
  84. #ifdef ResNodes_DeleteFile
  85.     // Only automatically delete the file if rn_TempFile is set.
  86.     if (doomedResNode->rn_TempFile)
  87.         deleteFileResNode(rnd,doomedResNode);
  88. #endif
  89. // Deallocation must be done AFTER the file has been deleted because the filename
  90. // may be allocated in the same ResNode!
  91. #ifdef ResNodes_Allocate
  92.     freeMemResNode(rnd,doomedResNode);
  93. #endif
  94. /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -*/
  95.     // Unlink it from the list.
  96.     if (doomedResNode->rn_Prev)
  97.         (doomedResNode->rn_Prev->rn_Next) = doomedResNode->rn_Next;
  98.     else
  99.         rnd->resnode_base = doomedResNode->rn_Next;    // If no Prev it's head of the list.
  100.  
  101.     if (doomedResNode->rn_Next)
  102.         (doomedResNode->rn_Next->rn_Prev) = doomedResNode->rn_Prev;
  103.  
  104.     // Free the memory for the ResNode itself.
  105.     FreeMemH(doomedResNode);
  106.     }
  107. }
  108.  
  109. /*= DeleteAllResNodes() ==============================================================-.
  110. || Delete ALL ResNodes and free all things connected with them.                          ||
  111. `-====================================================================================*/
  112. void deleteAllResNodes(ResNode_Data *rnd)
  113. {
  114.     while (rnd->resnode_base)
  115.         deleteResNode(rnd,rnd->resnode_base);
  116. }
  117.  
  118. #ifdef ResNodes_Allocate
  119. /*= AllocMemResNode() ================================================================-.
  120. || Allocate some memory for a ResNode.                                                  ||
  121. || Returns pointer to allocated memory, or NULL on failure.                              ||
  122. || Memory will be cleared automatically.                                              ||
  123. `-====================================================================================*/
  124. void *allocMemResNode(ResNode_Data *rnd,ResNode *daddyResNode,ULONG memSize)
  125. {
  126.     void *amrn_return = NULL;
  127.  
  128.     if (daddyResNode->rn_Mem)
  129.     {
  130.         // Should never allocate twice for one ResNode.
  131.         informUser(rnd->data, TEXT_INTERNAL_ERROR, FALSE, NULL);
  132.     }
  133.     else
  134.     {
  135.         if ((daddyResNode->rn_Mem) = AllocMemH(rnd->poolhead,memSize))
  136.             (daddyResNode->rn_Size) = memSize;
  137.         else
  138.             (daddyResNode->rn_Size) = 0;
  139.  
  140.         amrn_return = (daddyResNode->rn_Mem);
  141.     }
  142.  
  143.     return (amrn_return);
  144. }
  145. //--- Part of #ifdef above ---
  146. /*= AllocNewResNode() ================================================================-.
  147. || Create a new ResNode and Allocate memory for it.                                      ||
  148. || Returns NULL on failure.                                                              ||
  149. `-====================================================================================*/
  150. ResNode *allocNewResNode(ResNode_Data *rnd,ULONG memSize)
  151. {
  152.     ResNode *babyResNode;
  153.  
  154.     if (babyResNode = createResNode(rnd))
  155.     {
  156.         if (!(allocMemResNode(rnd,babyResNode,memSize)))
  157.         {
  158.             deleteResNode(rnd,babyResNode);
  159.             babyResNode = NULL;
  160.         }
  161.     }
  162.     return babyResNode;
  163. }
  164. //--- Part of #ifdef above ---
  165. /*= FreeMemResNode() =================================================================-.
  166. || Free memory allocated for a ResNode.                                                  ||
  167. || Resets rn_Mem and rn_Size to NULL.                                                  ||
  168. `-====================================================================================*/
  169. void freeMemResNode(ResNode_Data *rnd,ResNode *dietResNode)
  170. {
  171.     if (dietResNode->rn_Mem)        // Don't free if nothing to free).
  172.         FreeMemH(dietResNode->rn_Mem);
  173.  
  174.     dietResNode->rn_Size = (ULONG)(dietResNode->rn_Mem = NULL);
  175. }
  176. #endif
  177.  
  178. #ifdef ResNodes_Lock
  179. /*= lockFileResNode() ================================================================-.
  180. || Attempts to lock the ResNode's file (rn_Name) with the given mode.                  ||
  181. || If the file is in use it will try up to RN_INUSE_RETRIES times, waiting              ||
  182. || RN_INUSE_DELAY seconds between each try.                                              ||
  183. || Lockmode should be either ACCESS_READ or ACCESS_WRITE.                              ||
  184. || Returns the lock, or NULL on failure.                                              ||
  185. `-====================================================================================*/
  186. BPTR lockFileResNode(ResNode_Data *rnd,ResNode *rn,LONG lockmode)
  187. {
  188.     BPTR lfrn_return = NULL;
  189.     int  i;
  190.  
  191.     // Internal error if no ResNode, no filename or already locked.
  192.     if ( (!(rn)) || (!(rn->rn_Name)) || (rn->rn_Lock) )
  193.         informUser(rnd->data, TEXT_INTERNAL_ERROR, NULL, NULL);
  194.     else
  195.     {
  196.         i = 0;
  197.         while ( (i <= RN_INUSE_RETRIES) && \
  198.             ( !(rn->rn_Lock = Lock(rn->rn_Name,lockmode)) ) )
  199.         {
  200.             if (IoErr() != ERROR_OBJECT_IN_USE)
  201.                 i = RN_INUSE_RETRIES + 1;    // Don't try any more times.
  202.             else
  203.             {
  204.                 i++;
  205.                 Delay(50 * RN_INUSE_DELAY);
  206.             }
  207.         }
  208.         lfrn_return = (rn->rn_Lock);
  209.     }
  210.     return(lfrn_return);
  211. }
  212. //--- Part of #ifdef above ---
  213. /*= unlockFileResNode() ==============================================================-.
  214. || Frees the ResNode's file lock, if it has one.                                      ||
  215. || Passing a NULL ResNode or a ResNode with no lock is harmless.                      ||
  216. `-====================================================================================*/
  217. void unlockFileResNode(ResNode_Data *rnd,ResNode *lockedResNode)
  218. {
  219.     if ( (lockedResNode) && (lockedResNode->rn_Lock) )
  220.     {
  221.         UnLock(lockedResNode->rn_Lock);
  222.         lockedResNode->rn_Lock = NULL;
  223.     }
  224. }
  225. #endif
  226.  
  227. #ifdef ResNodes_Examine
  228. /*= examineResNode() =================================================================-.
  229. || Attempts to allocate and fill-in the FileInfoBlock (rn_FIB) for a ResNode.          ||
  230. || If the ResNode doesn't have a file lock already one will be obtained in READ mode  ||
  231. || (this requires a valid filename in the ResNode).                                      ||
  232. || If anything fails, memory allocated for the FIB will be freed and the lock, if      ||
  233. || created by this routine, will be freed.                                              ||
  234. || Returns pointer to FIB, or NULL on failure.                                          ||
  235. `-====================================================================================*/
  236. struct FileInfoBlock *examineResNode(ResNode_Data *rnd,ResNode *rn)
  237. {
  238.     BPTR wegotlock = NULL;
  239.     void *ern_return = NULL;
  240.  
  241.     // Internal error if no ResNode, no filename or already examined.
  242.     if ( (!(rn)) || (!(rn->rn_Name)) || (rn->rn_FIB) )
  243.         informUser(rnd->data, TEXT_INTERNAL_ERROR, NULL, NULL);
  244.     else
  245.     {
  246.         // First, allocate a File Info Block.
  247.         if (rn->rn_FIB = (struct FileInfoBlock *)AllocDosObject(DOS_FIB,NULL))
  248.         {
  249.             // If there isn't a lock, get one in READ mode and remember that this
  250.             // routine got the lock so it'll get freed if the Examine() fails.
  251.             if ( (rn->rn_Lock) || (wegotlock = lockFileResNode(rnd,rn,ACCESS_READ)) )
  252.             {
  253.                 if ( !(Examine(rn->rn_Lock,rn->rn_FIB)) )
  254.                 {
  255.                     // If we couldn't do the Examine(), free what we allocated.
  256.                     FreeDosObject(DOS_FIB,rn->rn_FIB);
  257.                     (rn->rn_FIB) = NULL;
  258.                     if (wegotlock)
  259.                         unlockFileResNode(rnd,rn);
  260.                 }
  261.             }
  262.             // If we couldn't do the Lock(), free what we allocated.
  263.             else
  264.             {
  265.                     FreeDosObject(DOS_FIB,rn->rn_FIB);
  266.                     (rn->rn_FIB) = NULL;
  267.             }
  268.         }
  269.         ern_return = (rn->rn_FIB);
  270.     }
  271.     return(ern_return);
  272. }
  273. //--- Part of #ifdef above ---
  274. /*= freeFIBResNode() =================================================================-.
  275. || Frees ResNode's FileInfoBlock (rn_FIB).                                              ||
  276. || Does *NOT* unlock the ResNode's lock, even if examineResNode got the lock.          ||
  277. || Passing a NULL ResNode or a ResNode with no FIB is harmless.                          ||
  278. `-====================================================================================*/
  279. void freeFIBResNode(ResNode_Data *rnd,ResNode *rn)
  280. {
  281.     if ( (rn) && (rn->rn_FIB) )
  282.     {
  283.         FreeDosObject(DOS_FIB,rn->rn_FIB);
  284.         (rn->rn_FIB) = NULL;
  285.     }
  286. }
  287. #endif
  288.  
  289. #ifdef ResNodes_Open
  290. /*= openFileResNode() ================================================================-.
  291. || Attempts to open the ResNode's file (using rn_Name as the filename).                  ||
  292. || mode must be MODE_OLDFILE, MODE_NEWFILE, or MODE_READWRITE (shared but can create).||
  293. || If the file is in use it will try up to RN_INUSE_RETRIES times, waiting              ||
  294. || RN_INUSE_DELAY seconds between each try.                                              ||
  295. || Returns file handle, or NULL on failure.                                              ||
  296. ||------------------------------------------------------------------------------------||
  297. || Note that it is safe to open a ResNode file where the filename is in rn_Mem, too,  ||
  298. || even if you set rn_TempFile, as ResNode memory is freed *after* the file is          ||
  299. || deleted (if required) in deleteResNode(). Of course, you must make sure you don't  ||
  300. || free the filename memory if the file will be deleted later explicitly by you or      ||
  301. || implicitly by deleteResNode().                                                      ||
  302. `-====================================================================================*/
  303. BPTR openFileResNode(ResNode_Data *rnd,ResNode *rn,LONG mode)
  304. {
  305.     BPTR ofrn_return = NULL;
  306.     int i;
  307.  
  308.     // Internal error if no ResNode, no filename or already openned.
  309.     if ( (!(rn)) || (!(rn->rn_Name)) || (rn->rn_FHandle) )
  310.         informUser(rnd->data, TEXT_INTERNAL_ERROR, NULL, NULL);
  311.     else
  312.     {
  313.         i = 0;
  314.         while ( (i <= RN_INUSE_RETRIES) && \
  315.             ( !((rn->rn_FHandle) = Open(rn->rn_Name,mode)) ) )
  316.         {
  317.             if (IoErr() != ERROR_OBJECT_IN_USE)
  318.                 i = RN_INUSE_RETRIES + 1;    // Don't try any more times.
  319.             else
  320.             {
  321.                 i++;
  322.                 Delay(50 * RN_INUSE_DELAY);
  323.             }
  324.         }
  325.         ofrn_return = (rn->rn_FHandle);
  326.     }
  327.     return(ofrn_return);
  328. }
  329. //--- Part of #ifdef above ---
  330. /*= closeFileResNode() ===============================================================-.
  331. || Closes the ResNode's file.                                                          ||
  332. || Doesn't bother checking whether or not it failed. (What's it meant to do if it      ||
  333. || does, huh?)                                                                          ||
  334. || Passing a NULL ResNode or a ResNode with NULL file handle is harmless.              ||
  335. `-====================================================================================*/
  336. void closeFileResNode(ResNode_Data *rnd,ResNode *rn)
  337. {
  338.     if ( (rn) && (rn->rn_FHandle) )
  339.     {
  340.         Close(rn->rn_FHandle);
  341.         (rn->rn_FHandle) = NULL;
  342.     }
  343. }
  344. #endif
  345.  
  346. #ifdef ResNodes_DeleteFile
  347. /*= deleteFileResNode() ==============================================================-.
  348. || Deletes the ResNode's file (rn_Name).                                              ||
  349. || This routine will only be called automatically on ResNodes with rn_TempFile set.      ||
  350. || Passing a NULL ResNode or a ResNode with no filename is harmless.                  ||
  351. || Passing a ResNode with rn_Name pointing to invalid/freed memory is not!              ||
  352. || If the file is in use it will try up to RN_INUSE_RETRIES times, waiting              ||
  353. || RN_INUSE_DELAY seconds between each try.                                              ||
  354. || If the file cannot be deleted nothing special will happen and the file'll be left. ||
  355. ||------------------------------------------------------------------------------------||
  356. || Note that it is safe to open a ResNode file where the filename is in rn_Mem, too,  ||
  357. || even if you set rn_TempFile, as ResNode memory is freed *after* the file is          ||
  358. || deleted (if required) in deleteResNode(). Of course, you must make sure you don't  ||
  359. || free the filename memory if the file will be deleted later explicitly by you or      ||
  360. || implicitly by deleteResNode().                                                      ||
  361. `-====================================================================================*/
  362. void deleteFileResNode(ResNode_Data *rnd,ResNode *rn)
  363. {
  364.     int i;
  365.  
  366.     if ( (rn) && (rn->rn_Name) )
  367.     {
  368.         i = 0;
  369.  
  370.         while ( (i <= RN_INUSE_RETRIES) && (!(DeleteFile(rn->rn_Name))) )
  371.         {
  372.             if (IoErr() != ERROR_OBJECT_IN_USE)
  373.                 i = RN_INUSE_RETRIES + 1;    // Don't try any more times.
  374.             else
  375.             {
  376.                 i++;
  377.                 Delay(50 * RN_INUSE_DELAY);
  378.             }
  379.         }
  380.     }
  381. }
  382. #endif
  383.